#include "Camera.h"

Camera::Camera()
{
	_pos = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
	_right = D3DXVECTOR3(1.0f, 0.0f, 0.0f);
	_up = D3DXVECTOR3(0.0f, 1.0f, 0.0f);
	_look = D3DXVECTOR3(0.0f, 0.0f, 1.0f);

	D3DXMatrixPerspectiveFovLH(&matProj, D3DX_PI/4.0f, SCREEN_WIDTH/SCREEN_HEIGHT, 1.0f, 10000.0f);
	_cameraType = AIRCRAFT;
	//_cameraType = LANDOBJECT;
}

Camera::~Camera(void)
{
}

void Camera::setPosition(FLOAT x, FLOAT y, FLOAT z)
{
	walk(z);
	fly(y);
	strafe(x);
}

D3DXMATRIX Camera::getViewMatrix()
{
	D3DXMATRIX view;
	getViewMatrix(&view);
	return view;
}

D3DXMATRIX Camera::getProjMatrix()
{
	return matProj;
}

D3DXMATRIX Camera::getViewProjMatrix()
{
	return getViewMatrix() * getProjMatrix();
}

D3DXMATRIX Camera::getInvViewProjMatrix()
{
	D3DXMATRIX invViewProj;
	D3DXMatrixInverse(&invViewProj, NULL, &getViewProjMatrix());
	return invViewProj;
}

D3DXVECTOR3 Camera::getPosition3()
{
	return D3DXVECTOR3(_pos.x, _pos.y, _pos.z);
}

D3DXVECTOR4 Camera::getPosition4()
{
	return D3DXVECTOR4(_pos.x, _pos.y, _pos.z, 0.0f);
}

void Camera:: updateControls()
{
	const FLOAT timeDelta = 0.05f;

	if( ::GetAsyncKeyState('W') & 0x8000f )
		walk(4.0f * timeDelta);
	if( ::GetAsyncKeyState('S') & 0x8000f )
		walk(-4.0f * timeDelta);
	if( ::GetAsyncKeyState('A') & 0x8000f )
		strafe(-4.0f * timeDelta);
	if( ::GetAsyncKeyState('D') & 0x8000f )
		strafe(4.0f * timeDelta);
	if( ::GetAsyncKeyState('R') & 0x8000f )
		fly(4.0f * timeDelta);
	if( ::GetAsyncKeyState('F') & 0x8000f )
		fly(-4.0f * timeDelta);
	if( ::GetAsyncKeyState(VK_UP) & 0x8000f )
		pitch(1.0f * timeDelta);
	if( ::GetAsyncKeyState(VK_DOWN) & 0x8000f )
		pitch(-1.0f * timeDelta);
	if( ::GetAsyncKeyState(VK_LEFT) & 0x8000f )
		yaw(-1.0f * timeDelta);
	if( ::GetAsyncKeyState(VK_RIGHT) & 0x8000f )
		yaw(1.0f * timeDelta);
	if( ::GetAsyncKeyState('N') & 0x8000f )
		roll(1.0f * timeDelta);
	if( ::GetAsyncKeyState('M') & 0x8000f )
		roll(-1.0f * timeDelta);
}


void Camera::getViewMatrix(D3DXMATRIX* V)
{
	// Keep camera's axes orthogonal to each other:
	D3DXVec3Normalize(&_look, &_look);
	D3DXVec3Cross(&_up, &_look, &_right);
	D3DXVec3Normalize(&_up, &_up);
	D3DXVec3Cross(&_right, &_up, &_look);
	D3DXVec3Normalize(&_right, &_right);
	// Build the view matrix:
	FLOAT x = -D3DXVec3Dot(&_right, &_pos);
	FLOAT y = -D3DXVec3Dot(&_up, &_pos);
	FLOAT z = -D3DXVec3Dot(&_look, &_pos);
	(*V)(0, 0) = _right.x;
	(*V)(0, 1) = _up.x;
	(*V)(0, 2) = _look.x;
	(*V)(0, 3) = 0.0f;
	(*V)(1, 0) = _right.y;
	(*V)(1, 1) = _up.y;
	(*V)(1, 2) = _look.y;
	(*V)(1, 3) = 0.0f;
	(*V)(2, 0) = _right.z;
	(*V)(2, 1) = _up.z;
	(*V)(2, 2) = _look.z;
	(*V)(2, 3) = 0.0f;
	(*V)(3, 0) = x;
	(*V)(3, 1) = y;
	(*V)(3, 2) = z;
	(*V)(3, 3) = 1.0f;
}

void Camera::pitch(FLOAT angle)
{
	D3DXMATRIX T;
	D3DXMatrixRotationAxis(&T, &_right, angle);
	// rotate _up and _look around _right vector
	D3DXVec3TransformCoord(&_up,&_up, &T);
	D3DXVec3TransformCoord(&_look,&_look, &T);
}
void Camera::yaw(FLOAT angle)
{
	D3DXMATRIX T;
	// rotate around world y (0, 1, 0) always for land object
	//if( _cameraType == LANDOBJECT )
		D3DXMatrixRotationY(&T, angle);
	// rotate around own up vector for aircraft
	//if( _cameraType == AIRCRAFT )
	//	D3DXMatrixRotationAxis(&T, &_up, angle);
	// rotate _right and _look around _up or y-axis
	D3DXVec3TransformCoord(&_right,&_right, &T);
	D3DXVec3TransformCoord(&_look,&_look, &T);
}
void Camera::roll(FLOAT angle)
{
	// only roll for aircraft type
	//if( _cameraType == AIRCRAFT )
	{
		D3DXMATRIX T;
		D3DXMatrixRotationAxis(&T, &_look, angle);
		// rotate _up and _right around _look vector
		D3DXVec3TransformCoord(&_right,&_right, &T);
		D3DXVec3TransformCoord(&_up,&_up, &T);
	}
}

void Camera::walk(FLOAT units)
{
	// move only on xz plane for land object
	if( _cameraType == LANDOBJECT )
		_pos += D3DXVECTOR3(_look.x, 0.0f, _look.z) * units;
	if( _cameraType == AIRCRAFT )
		_pos += _look * units;
}
void Camera::strafe(FLOAT units)
{
	// move only on xz plane for land object
	if( _cameraType == LANDOBJECT )
		_pos += D3DXVECTOR3(_right.x, 0.0f, _right.z) * units;
	if( _cameraType == AIRCRAFT )
		_pos += _right * units;
}

void Camera::fly(FLOAT units)
{
	//if( _cameraType == AIRCRAFT )
	{
		_pos += _up * units;
	}
}